package cn.fyk.sso.client.two.filter;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import cn.fyk.sso.client.two.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;

import cn.hutool.json.JSONUtil;

/**
 * @Description:	拦截业务处理
 * @Author:			方宇康
 * @CreateDate:		2020/1/6 11:21
 * @Version:      	1.0.0.1
 * @Company:       联通智网科技有限公司
 */
@Slf4j
public class SsoClientFilter implements Filter
{
	private final String SUCCESS_URL = "/sso/index";

	private final String SSO_SERVER_LOGIN_URL = "http://localhost:8080/ssoServer/sso/login";

	private final String SSO_SERVER_AUTHENTICATION_URL = "http://localhost:8080/ssoServer/sso/authentication";

	private final String SUFFIX_LOGIN = "/login";

	private final String SUFFIX_CSS = "css";

	private final String SUFFIX_JS = "js";

	private final Integer SUCCESS_CODE = 200;

	public static ConcurrentHashMap<String, HttpSession> TICKET_SESSION_CACHE = new ConcurrentHashMap<>();

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
	{
		HttpServletRequest request = (HttpServletRequest )servletRequest;
		HttpServletResponse response = (HttpServletResponse )servletResponse;
		HttpSession session = request.getSession();
		String path = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
		String uri = request.getRequestURI();
		String requestLogoutTicket = request.getParameter("requestLogout");
		// 如果是被动单点退出
		if(!StringUtils.isEmpty(requestLogoutTicket))
		{
			log.info("SsoClientFilter|doFilter|执行客户端二|单点退出操作");
			this.ssoLogout(requestLogoutTicket);
			response.sendRedirect(SSO_SERVER_LOGIN_URL.concat("?service=").concat(path));
			return;
		}
		String ticket = request.getParameter("ticket");
		if(!StringUtils.isEmpty(ticket)) {
			User user = this.getUserByTicket(ticket);
			if (user == null) {
				response.sendRedirect(SSO_SERVER_LOGIN_URL.concat("errorMsg=非法访问"));
			} else {
				session.setAttribute("LOGIN_INFO", user);
				response.sendRedirect(path.concat(SUCCESS_URL));
				TICKET_SESSION_CACHE.put(ticket, session);
			}
			return;
		}
		User user = (User)session.getAttribute("LOGIN_INFO");
		if (uri.endsWith(this.SUFFIX_LOGIN)) {
			response.sendRedirect(SSO_SERVER_LOGIN_URL.concat("?service=").concat(path));
			return;
		}
		if (Objects.nonNull(user) || uri.endsWith(this.SUFFIX_CSS) || uri.endsWith(this.SUFFIX_JS))
		{
			filterChain.doFilter(servletRequest, servletResponse);
		}
		else {
			response.sendRedirect(SSO_SERVER_AUTHENTICATION_URL.concat("?service=").concat(path));
		}
		return;
	}

	/**
	 * 根据票据获取用户信息
	 *
	 * @param ticket
	 * @return
	 * @exception
	 * @date        2020/1/6 14:29
	 */
	private User getUserByTicket(String ticket)
	{
		User user = null;
		//传入tick获取用户信息
		CloseableHttpClient httpClient = HttpClients.createDefault();
		//添加HTTP GET请求 访问百度首页
		URI uriHttp = null;
		try {
			uriHttp = new URI("http://localhost:8080/ssoServer/sso/validateTicket");
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		}
		URIBuilder uriBuilder = new URIBuilder(uriHttp);
		uriBuilder.setParameter("ticket", ticket);
		URI uri = null;
		try {
			uri = uriBuilder.build();
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		}
		HttpGet httpGet = new HttpGet(uri);
		CloseableHttpResponse closeableHttpResponse = null;
		try {
			//执行请求访问
			closeableHttpResponse = httpClient.execute(httpGet);
			//获取返回HTTP状态码
			int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
			if(statusCode == this.SUCCESS_CODE ) {
				HttpEntity entity = closeableHttpResponse.getEntity();
				String content = EntityUtils.toString(entity,"UTF-8");
				user = JSONUtil.toBean(content, User.class);
				log.info("SsoClientFilter|getUserByTicket|执行客户端二|从服务端获取用户信息|请求出参：={}", user);
				EntityUtils.consume(entity);
			}
		} catch (ClientProtocolException e) {
			log.error("SsoClientFilter|ClientProtocolException|异常", e);
		} catch (IOException e) {
			log.error("SsoClientFilter|IOException|异常", e);
		} finally {
			try {
				closeableHttpResponse.close();
			} catch (IOException e) {
				log.error("SsoClientFilter|finally|IOException|异常", e);
			}
		}
		return user;
	}

	/**
	 * 单点登录退出
	 *
	 * @param ticket
	 * @return
	 * @exception
	 * @date        2020/1/6 14:29
	 */
	private void ssoLogout(String ticket)
	{
		if(TICKET_SESSION_CACHE.containsKey(ticket))
		{
			HttpSession sess = TICKET_SESSION_CACHE.get(ticket);
			if(null != sess)
			{
				sess.invalidate();
			}
			TICKET_SESSION_CACHE.remove(ticket);
		}
	}
}
